package com.lytfly.flowable.modules.flow.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lytfly.flowable.domain.BaseProcessVO;
import com.lytfly.flowable.domain.CommentTypeEnum;
import com.lytfly.flowable.domain.FlowConstant;
import com.lytfly.flowable.exception.FlowException;
import com.lytfly.flowable.modules.flow.entity.FlowCommentInfo;
import com.lytfly.flowable.modules.flow.entity.FlowExtendHisprocinst;
import com.lytfly.flowable.modules.flow.mapper.IFlowableHisActinstMapper;
import com.lytfly.flowable.modules.flow.mapper.IFlowableRunActinstMapper;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @program: flow
 * @description: 抽象的流程服务
 * @author: Bruce.Liu
 * @create: 2021-04-20 14:48
 **/
public abstract class BaseProcessService {
    @Autowired
    protected IFlowCommentInfoService commentInfoService;
    @Autowired
    protected IFlowExtendHisprocinstService extendHisprocinstService;
    @Autowired
    protected CacheManager cacheManager;

    @Autowired
    protected ManagementService managementService;
    @Autowired
    protected TaskService taskService;
    @Autowired
    protected RuntimeService runtimeService;

    @Autowired
    private IFlowableActinstService flowableActinstService;


    protected void addFlowCommentInfo(FlowCommentInfo commentInfo) {
        commentInfo.insert();
    }

    /**
     * 执行跳转
     */
    protected void moveExecutionsToSingleActivityId(List<String> executionIds, String activityId) {
        runtimeService.createChangeActivityStateBuilder()
                .moveExecutionsToSingleActivityId(executionIds, activityId)
                .changeState();
    }

    /**
     * 添加审批意见
     *
     * @param baseProcessVO 参数
     */
    protected void addFlowCommentInfoAndProcessStatus(BaseProcessVO baseProcessVO) {
        FlowCommentInfo commentInfo = new FlowCommentInfo(baseProcessVO.getCommentTypeEnum().name(),
                baseProcessVO.getUserCode(),
                baseProcessVO.getProcessInstanceId(),
                baseProcessVO.getMessage());
        commentInfo.setTaskId(baseProcessVO.getTaskId());
        commentInfo.setActivityId(baseProcessVO.getActivityId());
        commentInfo.setActivityName(baseProcessVO.getActivityName());
        commentInfoService.saveComment(commentInfo);
        //修改流程实例的状态,
        if (baseProcessVO.getCommentTypeEnum() != null && !baseProcessVO.getCommentTypeEnum().equals(CommentTypeEnum.YY)) {
            if (StrUtil.isBlank(baseProcessVO.getProcessInstanceId())) {
                throw new FlowException("请传入流程实例id");
            }
            FlowExtendHisprocinst extendHisprocinst = new FlowExtendHisprocinst(baseProcessVO.getProcessInstanceId(),
                    baseProcessVO.getProcessStatusEnum().toString());
            extendHisprocinstService.updateAllStatusByProcessInstanceId(extendHisprocinst);
        }
    }

    protected void evictHighLightedNodeCache(String processInstanceId) {
        Cache cache = cacheManager.getCache(FlowConstant.CACHE_PROCESS_HIGHLIGHTEDNODES);
        assert cache != null;
        cache.evict(processInstanceId);
    }

    protected void evictOneActivityVoCache(String processInstanceId, String activityId) {
        Cache cache = cacheManager.getCache(FlowConstant.CACHE_PROCESS_ACTIVITYS);
        assert cache != null;
        String key = processInstanceId + "-" + activityId;
        cache.evict(key);
    }

    /**
     * 删除跳转的历史节点信息
     *
     * @param disActivityId     跳转的节点id
     * @param processInstanceId 流程实例id
     */
    protected void deleteActivity(String disActivityId, String processInstanceId) {
        String tableName = managementService.getTableName(ActivityInstanceEntity.class);
        String sql = "select t.* from " + tableName + " t where t.PROC_INST_ID_=#{processInstanceId} and t.ACT_ID_ = #{disActivityId} " +
                " order by t.END_TIME_ ASC";
        List<ActivityInstance> disActivities = runtimeService.createNativeActivityInstanceQuery().sql(sql)
                .parameter("processInstanceId", processInstanceId)
                .parameter("disActivityId", disActivityId).list();
        //删除运行时和历史节点信息
        if (CollUtil.isNotEmpty(disActivities)) {
            ActivityInstance activityInstance = disActivities.get(0);
            sql = "select t.* from " + tableName + " t where t.PROC_INST_ID_=#{processInstanceId} and (t.END_TIME_ >= #{endTime} or t.END_TIME_ is null)";
            List<ActivityInstance> datas = runtimeService.createNativeActivityInstanceQuery().sql(sql).parameter("processInstanceId", processInstanceId)
                    .parameter("endTime", activityInstance.getEndTime()).list();
            List<String> runActivityIds = new ArrayList<>();
            if (CollUtil.isNotEmpty(datas)) {
                datas.forEach(ai -> runActivityIds.add(ai.getId()));
                //TODO 真正用的时候看看这2个接口写在哪里合适
                flowableActinstService.deleteActinstByIds(runActivityIds);
            }
        }
    }

    protected TaskEntity createSubTask(TaskEntity parentTask, String assignee) {
        return this.createSubTask(parentTask, parentTask.getId(), assignee);
    }

    /**
     * 创建任务
     *
     * @param assignee     任务的执行者
     * @param parentTask   父亲任务实体
     * @param parentTaskId 父亲id
     * @return
     */
    protected TaskEntity createSubTask(TaskEntity parentTask, String parentTaskId, String assignee) {
        TaskEntity task = null;
        if (parentTask != null) {
            task = (TaskEntity) taskService.newTask(IdWorker.get32UUID());
            task.setAssignee(assignee);
            task.setProcessInstanceId(parentTask.getProcessInstanceId());
            task.setProcessDefinitionId(parentTask.getProcessDefinitionId());
            task.setParentTaskId(parentTaskId);
            task.setCategory(parentTask.getCategory());
            task.setDescription(parentTask.getDescription());
            task.setName(parentTask.getName());
            task.setTaskDefinitionKey(parentTask.getTaskDefinitionKey());
            task.setTaskDefinitionId(parentTask.getTaskDefinitionId());
            task.setTenantId(parentTask.getTenantId());
            task.setCreateTime(new Date());
            task.setPriority(parentTask.getPriority());
            taskService.saveTask(task);
        }
        return task;
    }

}
